有關於ExcelJS這個套件的教學與說明,請先看我的上一篇文章:
[前端/ES6] 實作匯出excel下載按鈕的超好用套件:ExcelJS(上)- 基礎介紹
這一篇呢,我們著重於在react中使用這個套件
以及要來發揮我們react的優點,把這個按鈕包裝成一個通用的 UI component
會特別寫這篇的原因也主要是我自己一開始在查 「react export excel」、「react 匯出excel」
找到的文件我覺得不夠詳盡,而且沒有一個現成的、包裝好的UI可以使用
好啦,廢話不多說,先來做一個最基礎的範例吧!
讓我們把上次的onClick function和react直接做一個簡單的結合如下
react + 事件定義 (js版本)
線上 codesandbox Demo: 簡易react + onClick範例
import React from "react";
import ExcelJs from "exceljs";
function ExportExcelButton (){
function onClick(){
const workbook = new ExcelJs.Workbook(); // 創建試算表檔案
const sheet = workbook.addWorksheet('工作表範例1'); //在檔案中新增工作表 參數放自訂名稱
sheet.addTable({ // 在工作表裡面指定位置、格式並用columsn與rows屬性填寫內容
name: 'table名稱', // 表格內看不到的,算是key值,讓你之後想要針對這個table去做額外設定的時候,可以指定到這個table
ref: 'A1', // 從A1開始
columns: [{name:'名字'},{name:'年齡'},{name:'電話'}],
rows: [['小明','20','0987654321'],['小美','23','0912345678']]
});
// 表格裡面的資料都填寫完成之後,訂出下載的callback function
// 異步的等待他處理完之後,創建url與連結,觸發下載
workbook.xlsx.writeBuffer().then((content) => {
const link = document.createElement("a");
const blobData = new Blob([content], {
type: "application/vnd.ms-excel;charset=utf-8;"
});
link.download = '測試的試算表.xlsx';
link.href = URL.createObjectURL(blobData);
link.click();
});
}
return (
<button onClick={onClick}> 下載excel </button>
)
};
你會發現其實這個就是把那些上次的function直接複製過來
然後render 一個button ,按下後會觸發
一樣是按下之後,就會得到這樣的檔案
TS版本
(markdown好像沒有支援TSX所以我只能先選typescript, 最後面return元件的語法顏色有點跑掉)
import React, { CSSProperties } from "react";
import ExcelJs from "exceljs";
export type SheetData = {
sheetName: string, // 工作表名稱
thead: Array<string>, // 欄位標題,例如:['姓名','年齡','電話']
tbody: Array<Array<string>>,
// 內容,例如:[['小明','20','0987654321'],['小美','23','0912345678']]
columnWidths?: Array<{number: number, width: number}> //用來指定欄寬的
}
interface ExportExcelButtonProps {
fileName: string, // 檔案名稱
sheetDatas:Array<SheetData> , // 要匯出的表格資料
disabled?: boolean, // 是不是要禁止按鈕動作
buttonRef?: React.MutableRefObject<any>, // 外面用useRef傳進來
style?: CSSProperties // 按鈕的style
}
export function ExportExcelButton (props: ExportExcelButtonProps){
function onClick(){
const workbook = new ExcelJs.Workbook();
props.sheetDatas.forEach((sheetData: SheetData)=>{
const sheet = workbook.addWorksheet(sheetData.sheetName);
sheet.addTable({
name: sheetData.sheetName,
ref: `A1`, // 從A1開始
headerRow: true,
columns: sheetData.thead.map((s)=>{ return {name: s}}),
rows: sheetData.tbody
});
if (sheetData.columnWidths) {
sheetData.columnWidths.forEach((column)=>{
sheet.getColumn(column.number).width = column.width
});
}
})
// 表格裡面的資料都填寫完成之後,訂出下載的callback function
// 異步的等待他處理完之後,創建url與連結,觸發下載
workbook.xlsx.writeBuffer().then((content: ExcelJs.Buffer) => {
const link = document.createElement("a");
const blob = new Blob([content], {
type: "application/vnd.ms-excel;charset=utf-8;"
});
link.download = `${props.fileName}.xlsx`;
link.href = URL.createObjectURL(blob);
link.click();
});
};
const style: CSSProperties = {
borderRadius: '5px',
...props.style
}
return (
<button
ref={props.buttonRef}
disabled={props.disabled}
onClick={onClick}
style={style}
>
匯出excel
</button>
)
};
export default ExportExcelButton;
JS版本
import React from "react";
import ExcelJs from "exceljs";
export function ExportExcelButton (props){
function onClick(){
const workbook = new ExcelJs.Workbook();
props.sheetDatas.forEach((sheetData)=>{
const sheet = workbook.addWorksheet(sheetData.sheetName);
sheet.addTable({
name: sheetData.sheetName,
ref: `A1`, // 從A1開始
headerRow: true,
columns: sheetData.thead.map((s)=>{ return {name: s}}),
rows: sheetData.tbody
});
if (sheetData.columnWidths) {
sheetData.columnWidths.forEach((column)=>{
sheet.getColumn(column.number).width = column.width
});
}
})
// 表格裡面的資料都填寫完成之後,訂出下載的callback function
// 異步的等待他處理完之後,創建url與連結,觸發下載
workbook.xlsx.writeBuffer().then((content) => {
const link = document.createElement("a");
const blob = new Blob([content], {
type: "application/vnd.ms-excel;charset=utf-8;"
});
link.download = `${props.fileName}.xlsx`;
link.href = URL.createObjectURL(blob);
link.click();
});
};
const style = {
borderRadius: '5px',
...props.style
}
return (
<button
ref={props.buttonRef}
disabled={props.disabled}
onClick={onClick}
style={style}
>
匯出excel
</button>
)
};
export default ExportExcelButton;
使用範例
import ExportExcelButton from "./ExportExcelButton";
function App(){
const downloadData = [
{
sheetName: `工作表1`,
thead: ['姓名','年齡','電話'],
tbody: [['小明','20','0987654321'],['小美','23','0912345678']],
columnWidths: [{number: 1, width:20},{number: 2, width:10},{number: 3, width:40}]
},
{
sheetName: `工作表2`,
thead: ['姓名','座號'],
tbody: [['小明','1'],['小美','2']],
columnWidths: [{number: 1, width:20}]
}
];
return (
<ExportExcelButton
fileName={'測試的試算表'}
sheetDatas={downloadData}
/>
)
}
如此一來,就可以將JSON格式的資料,轉成excel下載
而且對component外來說,只要整理好格式,試算表裡面就能夠有好幾張工作表
這邊也一樣提供以上的完整範例
線上codesandbox demo: TS component 、JS component
也歡迎大家根據這個示範,去準備自己的UI庫
我個人是使用react搭配 nx 這套toolchain 來進行開發的
題外話提一下nx這套toolchain
他有好用的環境建置,能做應用整合、共用LIB、方便搭配jest、e2e等優點
創建應用之後會有設置production這個configurations,幫忙分出測試的打包配置與正式發佈的配置
但事情就這麼發生了。
錯誤訊息:webpack.WebpackError is not a constructor
使用環境: 使用nx 這套toolchain 建置react專案
問題發生: import 這個套件之後,就發現build專案時,只要選擇production 配置
就會執行失敗,並噴出錯誤訊息: webpack.WebpackError is not a constructor
解決方式:
主要是引入該套件之後,會產生大量warning
而預設設定在webpack.json
中的production參數如下
注意到budgets的部分,裡面的maximumWarning 設置了最大warning為2mb
所以只要把這個數值拉高就可以了 (個人把他直接拉高到10mb)
等等,就這樣?
對。就這樣。我從錯誤訊息中根本看不出來是噴很多警告的關係,所以他花了我一小時在那邊爬文
如果各位引入套件之後,有類似的情形,可以先找找你家的webpack.json
檔
把警告和錯誤訊息的上限拉高看看
exceljs這個套件就介紹到這邊
本來有想要示範怎麼用react做一個可以異步取得資料的按鈕
不過想想感覺已經跟這個套件本身脫離關係了
比較像是遷就他 觸發
=> 建立表格、塞資料、觸發下載
這個機制所必須做的行為,跟..react 還有promise比較有關
如果有人有留言敲碗的話,我再寫一篇好了
就這樣!希望文章都有幫助到大家~讓大家少踩一點坑
還有讓exceljs的文章多一點繁體字的介紹...
喜歡這篇文的話可以幫我點一個喜歡~ 我會很開心XDD (真是虛榮的女人
以上!
您好:
在閱讀完文章及實作後,發現匯出rows: sheetData.tbody
僅能匯出最後一筆,也有使用forEach,不知道是不是我漏了什麼?
謝謝
你要貼一下你的程式碼嗎?不確定你帶入的格式之類的
不好意思,現在才看到回覆。已經有解決了,謝謝您